package com.cl.utility.config;

import com.cl.utility.annocation.NoAuthorization;
import com.cl.utility.pojo.Student;
import com.cl.utility.security.StudentThreadLocal;
import com.cl.utility.service.StudentService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 请求拦截器 统一token校验
 *
 * @author 陌路
 * @date 2022-03-19
 * @apiNote 统一token校验
 */
@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private StudentService studentService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        /** 思路
         * 首先判断请求的方法中是否包含了@NoAuthorization注解 若包含了此注解 则不作处理
         * 包含该@NoAuthorization注解 表示不需要做token的验证 直接return true 放行即可
         * 如果不包含该注解,说明需要对token进行校验,则继续执行下面的代码
         * 校验：首先判断请求头中是否包含 "Authorization" 请求头数据 不包含则结束校验 不予访问
         * 若包含 则需要解析token数据 拿到 user 对象,判断user对象是否为null
         * 为null 说明不存在,直接返回false,不予访问,重新登录
         * 不为空 则需要把当前user对象存储到 UserThreadLocal 线程中去 并返回true 验证成功
         */
        // 如果 handler 是 HandlerMethod 类型,则把 handler(Object类型)转为HandlerMethod类型
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 获取将要访问的方法名,根据方法名获取方法上的 NoAuthorization 注解,判断该注解是否存在
            NoAuthorization noAuthorization = handlerMethod
                    .getMethod()
                    .getAnnotation(NoAuthorization.class);
            //若方法中存在该 NoAuthorization 注解,则表示无需校验 返回true
            if (noAuthorization != null) {
                return true;
            }
        }
        //获取到请求头中的头信息(token)
        String token = request.getHeader("Authorization");
        //判断token是否存在
        if (StringUtils.isNotEmpty(token)) {
            //存在则根据token解析user数据
            Student student = this.studentService.queryStudentByToken(token);
            //判断解析的user数据是否为null
            if (null != student) {
                //不为空 则将user信息存储到线程中
                StudentThreadLocal.set(student);
                return true;
            }
        }
        //若请求头中不存在Authorization 直接返回false 提示状态码401无权限
        response.setStatus(401);
        return false;
    }

    /**
     * 所有方法执行完成之后最后执行此方法
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 所有业务执行完之后移除缓存数据,防止数据泄露
        StudentThreadLocal.remove();
    }
}
